package server

import (
	"context"
	"errors"
	"fmt"
	"longmen/server/config/global"
	"longmen/server/pkg/common/helper/const"
	"longmen/server/pkg/common/helper/encrypt"
	string2 "longmen/server/pkg/common/helper/string"
	"longmen/server/pkg/common/helper/util"
	"longmen/server/pkg/db/mysql"
	"longmen/server/pkg/db/mysql/db_main"
	"longmen/server/pkg/db/mysql/models/models_main"
	"longmen/server/pkg/db/redis/cache"
	pb "longmen/server/pkg/protobuf"
	"strings"
	"time"
)

func (s *Server) CheckCode(mobile, code string) error {
	if code == _const.POWER_CODE && cache.GetConfigPub().PowerMode == 1 {
		return nil
	}
	smscode, err := db_main.GetSmscodeParam(map[string]interface{}{
		"mobile": mobile,
		"code":   code,
		"status": _const.SMS_CODE_STATUS_FRESH,
		//"create_time": map[string]interface{}{">=": timehelper.Now().Add(timehelper.Duration(-10) * timehelper.Minute)},
	}, "create_time desc")
	if err != nil {
		return errors.New(global.Lang.T("verification_code_err"))
	}
	if smscode.Id <= 0 {
		return errors.New(global.Lang.T("verification_code_err"))
	}
	// "create_time": map[string]interface{}{">=": timehelper.Now().Add(timehelper.Duration(-5) * timehelper.Minute)},
	if smscode.CreateTime.Before(time.Now().Add(time.Duration(-5) * time.Minute)) {
		return errors.New(global.Lang.T("verification_code_timeout"))
	}

	smscode.Status = _const.SMS_CODE_STATUS_USED
	err = db_main.UpdateSmscode(smscode)
	if err != nil {
		return fmt.Errorf(global.Lang.T("network_timeout"))
	}
	return nil
}

// 验证SMS code，返回一个mobileHash，下一次来的时候验证这个值
func (s *Server) ReadyForTakeOff(ctx context.Context, req *pb.ReadyForTakeOffReq) (*pb.ReadyForTakeOffResp, error) {
	err := s.CheckCode(req.GetMobile(), req.GetSmscode())
	if err != nil {
		return nil, err
	}
	err = util.CheckMobile(req.Mobile)
	if err != nil {
		return nil, err
	}
	mobileHash := encrypt.GenHashWithLength(11)
	rHash := cache.GetMobileToHash(req.GetMobile())
	if len(rHash) > 1 {
		_ = cache.DelRegisterVerify(rHash) //删掉重置
	}
	err = cache.SetRegisterVerify(mobileHash, req.GetMobile())
	if err != nil {
		return nil, errors.New("设置验证缓存错误")
	}
	return &pb.ReadyForTakeOffResp{
		Data: &pb.CheckVerifyCodeResp{
			MobileHash: mobileHash,
		}}, nil
}

// 带了hash进来验证，如果通过，就去改密码
func (s *Server) ForgetPwdHash(ctx context.Context, r *pb.ForgetPwdHashReq) (*pb.ForgetPwdHashResp, error) {
	exists, err := global.BloomExists(global.BLOOM_MOBILE, r.Mobile)
	if !exists {
		return nil, errors.New(global.Lang.T("phone_number_is_not_registered"))
	}
	//验证手机号
	user, err := mysql.GetUserParam(map[string]interface{}{"mobile": r.Mobile})
	if err != nil {
		return nil, err
	}
	if user.Id <= 0 || user.Status == _const.ACCOUNT_DEACTIVED {
		return nil, errors.New(global.Lang.T("phone_number_is_not_registered"))
	}
	if !takeOffCodeOk(r.Mobile, r.MobileHash) {
		return nil, errors.New(global.Lang.T("network_timeout"))
	}
	password, err := encrypt.PwdDesECBEncrypt(user.Account, r.Pwd)
	if err != nil {
		return nil, err
	}
	if util.CheckPwd(r.Pwd) {
		user.Password = password
		err = db_main.UpdateUser([]string{"password"}, user)
	} else {
		return nil, errors.New("密码格式不符")
	}
	if err != nil {
		return nil, err
	}
	cache.DelUserLastToken(user.Id) //删掉这个last token，使快速登陆失效
	return &pb.ForgetPwdHashResp{
		Msg: global.Lang.T("success"),
	}, nil
}
func (s *Server) FastLogin(ctx context.Context, req *pb.FastLoginReq) (*pb.FastLoginResp, error) {
	//t := util.Stamp2Time(req.TNow)
	if req.TNow+300 < time.Now().Unix() { //60秒超时了； 测试的时候多给点时间
		return nil, fmt.Errorf(global.Lang.T("please_login_again"))
	}
	md5Token := strings.ToLower(encrypt.Md5(req.Token))
	sRaw := fmt.Sprintf("%d%s", req.TNow, md5Token)
	if req.Key != strings.ToLower(encrypt.Md5(sRaw)) {
		return nil, fmt.Errorf(global.Lang.T("please_login_again"))
	}
	user, err := s.GetUser(map[string]interface{}{"mobile": req.Mobile})
	if err != nil {
		return nil, err
	}
	if user.Id == 0 {
		return nil, fmt.Errorf(global.Lang.T("please_login_again"))
	}
	loginReq := LoginParam{
		SourceKey:  req.SourceKey,
		SourceId:   req.SourceId,
		Website:    req.Website,
		Platform:   req.Platform,
		Ip:         req.Ip,
		DeviceInfo: req.DeviceInfo,
	}
	oResp, err := s.GenLoginResp(user, loginReq)
	if err != nil {
		return nil, err
	}
	return &pb.FastLoginResp{Data: oResp}, nil
}

func (s *Server) SendSmsCode(ctx context.Context, req *pb.SendSmsCodeReq) (*pb.SendSmsCodeResp, error) {
	code := string2.GenSmsCode()
	areaCode := req.GetAreaCode()
	if len(areaCode) < 1 {
		areaCode = "86"
	}
	err := s.Sms.SendCode(areaCode, req.GetMobile(), code)
	if err != nil {
		return nil, err
	}
	codeM := &models_main.Smscode{
		Mobile:     req.GetMobile(),
		RequestIp:  req.GetIp(),
		CreateTime: time.Now(),
		Code:       code,
	}
	err = db_main.InsertSmscode(nil, codeM)
	if err != nil {
		return nil, err
	}
	return &pb.SendSmsCodeResp{}, nil
}

func (s *Server) SendBindCode(ctx context.Context, req *pb.SendSmsCodeReq) (*pb.SendSmsCodeResp, error) {
	//查询手机号是否被占用
	user, err := mysql.GetUserParam(map[string]interface{}{"account": req.GetMobile()})
	if err != nil {
		return nil, err
	}
	if user.Id > 0 {
		return nil, errors.New(global.Lang.T("phone_number_already_taken"))
	}
	//查询最近5分钟内是否发送过
	codeInfo1, err := db_main.GetSmscodeParam(map[string]interface{}{"mobile": req.GetMobile(), "status": 0, "create_time": map[string]interface{}{">": time.Now().Add(time.Duration(-5) * time.Minute)}}, "")
	if err != nil {
		return nil, err
	}
	if codeInfo1.Id > 0 {
		return nil, errors.New(global.Lang.T("verification_code_sent_too_often"))
	}
	codeInfo2, err := db_main.GetSmscodeParam(map[string]interface{}{"request_ip": req.GetIp(), "status": 0, "create_time": map[string]interface{}{">": time.Now().Add(time.Duration(-5) * time.Minute)}}, "")
	if err != nil {
		return nil, err
	}
	if codeInfo2.Id > 0 {
		return nil, errors.New(global.Lang.T("verification_code_sent_too_often"))
	}
	areaCode := req.GetAreaCode()
	if len(areaCode) < 1 {
		areaCode = "86"
	}
	return s.SendSmsCode(ctx, req)
}
